import logging
from dataclasses import dataclass

from src.application.order.converters import convert_order_entity_to_dto
from src.application.order.dto.order import OrderDTO
from src.application.order.enums import OrderStatus, OrderType
from src.application.order.uow import OrderUoW
from src.application.proxy.converters import convert_proxy_entity_to_dto
from src.application.proxy.dto.proxy import ProxyDTO
from src.domain.order.value_objects import OrderId
from src.infrastructure.db.services.proxy import change_expired_proxy
from src.infrastructure.db.uow import SQLAlchemyUoW
from src.infrastructure.ssh.async_ssh_connector import change_expired_proxies, delete_vpn_config
from src.infrastructure.utils.helpers import get_server_proxies

logger = logging.getLogger(__name__)


@dataclass(frozen=True)
class ArchiveOrder:
    order_id: int


class ArchiveOrderHandler:
    """
    Архивирование заказа
    """

    def __init__(
        self,
        *,
        uow: SQLAlchemyUoW,
    ) -> None:
        self._uow = uow

    async def __call__(self, command: ArchiveOrder) -> OrderDTO:
        order = await self._uow.order_repo.acquire_order_by_id(OrderId(command.order_id))
        user = await self._uow.user_repo.acquire_user_by_id(order.buyer_id)

        order.clear_proxies()
        order.clear_allowed_ips()
        order.update_status(OrderStatus.archive)
        user.delete_proxies(order.proxies)

        # TODO Вынести в репозиторий
        allowed_ip = await get_allowed_ip_by_order(session, user.tg_id, order.order_id)

        if len(order.proxies) > 0:
            old_proxies = [
                ProxyDTO(
                    id=proxy.id,
                    server_id=proxy.server_id,
                    login=proxy.login,
                    password=proxy.password,
                    reload_link=proxy.reload_link,
                    port_https=proxy.port_https,
                )
                for proxy in order.proxies
            ]

            order_proxies = [convert_proxy_entity_to_dto(proxy) for proxy in order.proxies]

            server_proxies = await get_server_proxies(old_proxies, order_proxies)

            for server_id, proxies in server_proxies.items():
                # TODO Тут получать сервер
                server = await self._uow.server_reader.get_server_by_id(server_id)
                await change_expired_proxy(session, proxies)  # TODO Функция должна возвращать список новых ProxyDTO
                await change_expired_proxies(server, proxies, allowed_ip)  # TODO Передаем список сюда

        if order.order_type == OrderType.vpn:
            if await delete_vpn_config(order.vpn_server, user.tg_id.value):
                logger.info(f"Deleted used vpn config {user.tg_id.value}")
                order.vpn_server = None

        try:
            await self._uow.order_repo.update_order(order)
            await self._uow.user_repo.update_user(user)
        except Exception as err:
            await self._uow.rollback()
            raise err

        await self._uow.commit()

        logger.info(f"Order №{command.order_id} was archived")

        order_dto = convert_order_entity_to_dto(order)

        return order_dto
